﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using School.Entities;
using School.Common;
using School.Accounting.Reports;

namespace School.Accounting
{
    public static class PaymentOrder
    {
        private static SchoolEntities db = new SchoolEntities();

        public static IEnumerable<ACC_Expense_Payments> GetPayments(long Expense_Id, long Student_Id)
        {
            long cy = (from x in db.ORG_EductionalYear where x.IsCurrent == true select x.Id).First();

            var apo = from x in db.ACC_Voucher
                      where
                          x.Student_Id == Student_Id &&
                          x.Expense_Id == Expense_Id &&
                          x.Current_Educational_Year == cy &&
                          x.Is_Active == true
                      select x.Payment_Order_Number;



            var paid = from x in db.ACC_Payment_Order where x.Student_Id == Student_Id && x.ACC_Expense_Payments.ACC_Expense.ID == Expense_Id && apo.Contains(x.Payment_Order_Number) select x.Payment_Id;

            IEnumerable<ACC_Expense_Payments> payments;

            if (paid.Count() > 0)
                payments = from x in db.ACC_Expense_Payments where paid.Contains(x.Id) == false && x.Expense_Id == Expense_Id select x;
            else
                payments = from x in db.ACC_Expense_Payments where x.Expense_Id == Expense_Id select x;

            return payments;
        }

        public static ACC_Expense_Payments GetPayment(long id)
        {
            return (from x in db.ACC_Expense_Payments where x.Id == id select x).First();
        }

        public static long AddPaymentOrder(ACC_Payment_Order po, List<ACC_Payment_Order_Discounts> discounts = null)
        {
            po.Date = DateTime.Now;
            var year = Structure.GetCurrentEductionalYear().First();
            po.Educational_Year = year.Id;
            po.Payment_Order_Number = Structure.GetPayment_Order_Number();
            db.AddToACC_Payment_Order(po);
            db.SaveChanges();

            if (discounts != null)
                ApplyDiscounts(po.Payment_Order_Number, discounts);

            return po.Payment_Order_Number;
        }

        public static void ApplyDiscounts(long payment, List<ACC_Payment_Order_Discounts> discounts)
        {
            try
            {
                db.ACC_Payment_Order.Single(x => x.Payment_Order_Number == payment);
                foreach (ACC_Payment_Order_Discounts d in discounts)
                {
                    d.Payment_Order_Number = payment;
                    db.AddToACC_Payment_Order_Discounts(d);
                }

                db.SaveChanges();
            }
            catch
            {
            }
        }

        public static IEnumerable<ACC_Payment_Order> All()
        {
            return from x in db.ACC_Payment_Order orderby x.Date select x;
        }

        public static IEnumerable<ACC_Payment_Order> GetByNumber(long number)
        {
            return from x in db.ACC_Payment_Order where x.Payment_Order_Number == number select x;
        }

        public static IEnumerable<ACC_Payment_Order> GetByStudent(long student)
        {
            return from x in db.ACC_Payment_Order where x.Student_Id == student select x;
        }

        public static IEnumerable<ACC_Payment_Order_Discounts> GetDiscounts(long number)
        {
            return from x in db.ACC_Payment_Order_Discounts where x.Payment_Order_Number == number select x;
        }

        public static PaymentOrderReportObject GetPaymentReport(long number)
        {
            var pos = Voucher.GetPaymentOrdersByNumber(number);

            if (pos.Count() == 0)
                return null;

            PaymentOrderReportObject ob;

            var po = pos.First();

            var student = db.TE_Student.Single(y => y.Id == po.Student_Id);
            ob = new PaymentOrderReportObject() { Expense = po.Expense_Name, Number = po.Number, Date = DateTime.Parse(po.Date.ToString()).ToString(), Value = po.Value.ToString(), Student = po.Student_Name, Campus = db.ORG_Campus.Single(x => x.Id == student.Campus_Id).Name, Certificate = db.ORG_Certificate.Single(x => x.Id == student.Certificate_Id).Name, Stage = db.ORG_Stage.Single(x => x.Id == student.Stage_Id).Name, Grade = db.ORG_Grade.Single(x => x.Id == student.Grade_ID).Name };

            return ob;
        }

        public static IEnumerable<PaymentOrderDiscountsObject> GetDiscountsReport(long number)
        {
            List<PaymentOrderDiscountsObject> pods = new List<PaymentOrderDiscountsObject>();

            var ds = from x in db.ACC_Payment_Order_Discounts where x.Payment_Order_Number == number select x;

            foreach (var d in ds)
            {
                pods.Add(new PaymentOrderDiscountsObject() { Name = d.ACC_Discount.Name, Code = d.ACC_Discount.Code, Type = d.Type, Value = d.Value });
            }

            return pods;
        }

        public static decimal GetPaidValue(long number)
        {

            return (from x in db.ACC_Voucher where x.Payment_Order_Number == number select x).Sum(x => x.Value);
        }

        public static IEnumerable<DiscountObject> GetUnappliedDiscounts(PaymentOrderObject po)
        {
            //var ed = Finance.GetExpenseDiscounts(po.ACC_Expense_Payments.Expense_Id, studentId: po.Student_Id);            

            /*foreach (var e in ed)
            {
                if (!po.ACC_Payment_Order_Discounts.Select(x => x.Discount_Id).Contains(e.Id))
                    ep.Add(e);
            }*/

            List<DiscountObject> ep = new List<DiscountObject>();

            var ed = Finance.GetExpenseDiscounts(po.Expense_Id, studentId: po.Student_Id);

            List<DiscountObject> applied = new List<DiscountObject>();

            try
            {
                foreach (var e in ed)
                {
                    if (!db.ACC_Payment_Order.Single(x => x.Payment_Order_Number == po.Number).ACC_Payment_Order_Discounts.Select(x => x.Discount_Id).Contains(e.Id))
                        ep.Add(e);
                }
                /*if (db.ACC_Expense.Where(x => x.ACC_Expenses_Screens.Count() > 0).Count() > 0)
                {
                    var expenseType = db.ACC_Expense.Single(x => x.ID == po.Expense_Id).ACC_Expenses_Screens.Single(x => x.Expense_Id == po.Expense_Id).SEC_Screen.Code;

                    switch (expenseType)
                    {
                        case "200":
                            var bId = db.SRV_Bus_Payment_Order.Single(y => y.Payment_order_num == po.Number).Id;
                            var ds = db.SRV_BUS_PAYMENT_ORDER_Discounts.Where(x => x.Payment_order_Id == bId).Select(x => x.Discount_Id);

                            if (ds.Count() > 0)
                            {
                                foreach (var d in ed)
                                {
                                    if (!ds.Contains(d.Id))
                                        ep.Add(new DiscountObject { Id = d.Id, Name = d.Name, Type = d.Type });
                                }
                            }
                            else
                            {
                                foreach (var d in ed)
                                {
                                    ep.Add(new DiscountObject { Id = d.Id, Name = d.Name, Type = d.Type });
                                }
                            }

                            break;

                        case "400":
                            var ds2 = db.SRV_Book_PaymentDiscount.Where(x => x.OrderID == db.SRV_BOOK_Payment_Order.Single(y => y.Payment_Order_Number == po.Number).Order_Id).Select(x => x.DiscountID);

                            if (ds2.Count() > 0)
                            {
                                foreach (var d in ed)
                                {
                                    if (!ds2.Contains(d.Id))
                                        ep.Add(new DiscountObject { Id = d.Id, Name = d.Name, Type = d.Type });
                                }
                            }
                            else
                            {
                                foreach (var d in ed)
                                {
                                    ep.Add(new DiscountObject { Id = d.Id, Name = d.Name, Type = d.Type });
                                }
                            }

                            break;
                    }

                }*/
            }
            catch
            {                
            }

            return ep;
        }

        public static PaymentOrderObject UpdatePaymentOrderValue(long number, decimal value)
        {
            PaymentOrderObject pu = new PaymentOrderObject();

            try
            {
                var opo = db.ACC_Payment_Order.Single(x => x.Payment_Order_Number == number);
                opo.Value = value;
                pu.Number = opo.Payment_Order_Number;
                pu.Student_Id = opo.Student_Id;
                pu.Student_Name = opo.TE_Student.Ar_FirstName + " " + opo.TE_Student.Ar_SecondName + " " + opo.TE_Student.Ar_ThirdNmae + " " + opo.TE_Student.Ar_FourthName;
                pu.Date = opo.Date;
                pu.Expense_Id = opo.ACC_Expense_Payments.Expense_Id;
                pu.Expense_Name = opo.ACC_Expense_Payments.ACC_Expense.Name;
            }
            catch
            {
            }

            try
            {
                var opo = db.SRV_BOOK_Payment_Order.Single(x => x.Payment_Order_Number == number);
                opo.Value = value;

                var expense = db.ACC_Expenses_Screens.SingleOrDefault(x => x.SEC_Screen.Code == "400").ACC_Expense;

                pu.Number = opo.Payment_Order_Number;
                pu.Student_Id = opo.Student_Id;
                pu.Student_Name = opo.TE_Student.Ar_FirstName + " " + opo.TE_Student.Ar_SecondName + " " + opo.TE_Student.Ar_ThirdNmae + " " + opo.TE_Student.Ar_FourthName;
                pu.Date = opo.Date;
                pu.Expense_Id = expense.ID;
                pu.Expense_Name = expense.Name;
            }
            catch
            {
            }

            try
            {
                var opo = db.SRV_Bus_Payment_Order.Single(x => x.Payment_order_num == number);
                opo.Value = value;

                var expense = db.ACC_Expenses_Screens.SingleOrDefault(x => x.SEC_Screen.Code == "200").ACC_Expense;

                pu.Number = opo.Payment_order_num;
                pu.Student_Id = opo.Student_Id;
                pu.Student_Name = opo.TE_Student.Ar_FirstName + " " + opo.TE_Student.Ar_SecondName + " " + opo.TE_Student.Ar_ThirdNmae + " " + opo.TE_Student.Ar_FourthName;
                pu.Date = opo.Date;
                pu.Expense_Id = expense.ID;
                pu.Expense_Name = expense.Name;
            }
            catch
            {
            }

            db.SaveChanges();
            return pu;
        }
    }
}
